package com.sinnatec.redis.annoation;

import com.sinnatec.redis.RedisLockService;
import com.sinnatec.redis.lock.RedisLock;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import com.sinnatec.redis.util.SpelUtil;

import java.lang.reflect.Method;
import java.util.concurrent.TimeoutException;

/**
 * @ClassName DistributedLockAspect
 * @Description TODO
 * @Author fangsong
 * @Date 2021/12/8 10:49
 * @Version 1.0
 */
@Aspect
public class DistributedLockAspect {

    private RedisLockService redisLockService;

    public DistributedLockAspect(RedisLockService redisLockService) {
        this.redisLockService = redisLockService;
    }

    @Pointcut(value = "@annotation(com.sinnatec.redis.annoation.DistributedLock)")
    public void pointCut(){}

    @Around(value="pointCut() && @annotation(anno)")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint, DistributedLock anno) throws Throwable {
        String spel = anno.lockName();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        String lockName = SpelUtil.evaluate(spel,method,joinPoint.getArgs());
        if(StringUtils.isBlank(lockName)){
            throw new IllegalArgumentException("lockName为空");
        }
        RedisLock lock = redisLockService.getLock(lockName);
        if(!lock.tryLock(anno.waitTime())){
            throw new TimeoutException("分布式锁等待超时");
        }
        Object result;
        try {
            //让代理方法执行
            result = joinPoint.proceed();
        } finally {
            lock.releaseLock();
        }
        return result;
    }
}
